import fs from 'fs-extra';
import path from 'path';

export class TsImportDoctor {
    async fixAll(tsRoot: string): Promise<void> {
        const fileMap: { [fileName: string]: string } = {};
        await this.collectTs(tsRoot, fileMap);
        await this.fixImports(tsRoot, fileMap);
    }

    async collectTs(dir: string, fileMap: { [fileName: string]: string }): Promise<void> {
        const files = await fs.readdir(dir);
        for (const f of files) {
            if (f.startsWith('.')) continue;
            const file = path.join(dir, f);
            const fstat = await fs.stat(file);
            if (fstat.isDirectory()) {
                await this.collectTs(file, fileMap);;
            } else if (path.extname(f) === '.ts') {
                fileMap[path.basename(file)] = file;
            }
        }
    }

    async fixImports(tsRoot: string, fileMap: { [fileName: string]: string }): Promise<void> {
        for (const fileName in fileMap) {
            const file = fileMap[fileName];
            const content = await fs.readFile(file, 'utf-8');
            let fixxed = false;
            const newContent = content.replace(/(?<=import.+from ('|"))\S+(?=\1)/g, (substring: string, ...args) => {
                if (substring.startsWith('.')) {
                    const fdir = path.dirname(file);
                    const importedFile = path.join(fdir, substring + '.ts');
                    if (!fs.existsSync(importedFile)) {
                        const importFileName = path.basename(importedFile);
                        if (fileMap[importFileName]) {
                            fixxed = true;
                            let fixxedPath = path.relative(fdir, fileMap[importFileName]).replaceAll('\\', '/');
                            if (!fixxedPath.startsWith('.')) fixxedPath = './' + fixxedPath;
                            return fixxedPath.substring(0, fixxedPath.length - 3);
                        }
                    }
                } else {
                    const importedFile = path.join(tsRoot, substring + '.ts');
                    if (!fs.existsSync(importedFile)) {
                        const importFileName = path.basename(importedFile);
                        if (fileMap[importFileName]) {
                            fixxed = true;
                            let fixxedPath = path.relative(tsRoot, fileMap[importFileName]).replaceAll('\\', '/');
                            return fixxedPath.substring(0, fixxedPath.length - 3);
                        }
                    }
                }
                return substring;
            });
            if (fixxed) {
                await fs.writeFile(file, newContent, 'utf-8');
            }
        }
    }
}
